﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Text;
using System.Web.Script.Serialization;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.Storage.Table;

namespace LoadGenerator
{
    public class Job : TableEntity
    {
        public Job()
        {
        }

        public int InstanceCount { get; set; }
        public string LoadConfigurations{ get; set; }
        public int Duration { get; set; }

        public string DllName { get; set; }
        public string ClassName { get; set; }
        public string MethodName { get; set; }
        public string Parameters { get; set; }
        public string ServiceName { get; set; }
        public bool IsRandomInvoke { get; set; }

        public string QueuedDateTime { get; set; }

        public string originalPK 
        {
            get 
            { 
                var pkArr = this.PartitionKey.Split(new char[] { '_' });
                return pkArr[0] + "_" + pkArr[1];
            }
        }
    }


    public class Sample : TableEntity
    {
        public Sample()
        {
        }
        
        public Sample(int threadID,string InstanceName, int threadCount)
        {
            this.CreationTicks = DateTime.UtcNow.Ticks;
            this.PartitionKey = InstanceName;
            //this.RowKey = Guid.NewGuid().ToString();
            this.RowKey = threadID.ToString();
            this.ThreadCount = threadCount;
            hasError = false;      
        }

        public long CreationTicks { get; set; }
        public int ResponseTime { get; set; }
        public int ThreadCount { get; set; }
        public bool hasError { get; set; }

    }

    [ServiceContract]
    public interface IJobService
    {
        [OperationContract]
        void AbortJob();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class JobService : IJobService
    {
         public event EventHandler OnJobAborted;

         public void AbortJob()
         {
             OnJobAborted(this, null);
         }
    }


    public class GeneratorConfigurations : CollectionBase
    {
        public int Add(GeneratorConfiguration generatorConfig)
        {
            generatorConfig.InstanceName = "IN_" + this.List.Count;
            return List.Add(generatorConfig);
        }

        public void Remove(GeneratorConfiguration generatorConfig)
        {
            List.Remove(generatorConfig);
        }

        public GeneratorConfiguration this[int index]
        {
            get
            {
                return (GeneratorConfiguration)List[index];
            }
            set
            {
                List[index] = value;
            }
        }

        public string Serialize()
        {
            JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
            List<GeneratorConfiguration> gclist = this.Cast<GeneratorConfiguration>().ToList();
            return jsSerializer.Serialize(gclist);
        }

        public static List<GeneratorConfiguration> Deserialize(string configs)
        {
            JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
            return (List<GeneratorConfiguration>)jsSerializer.Deserialize(configs, typeof(List<GeneratorConfiguration>));
        }

        
        public class GeneratorConfiguration
        {
            public string InstanceName { get; set; }

            public int StartUpDelay { get; set; }
            public int NumberOfThreads { get; set; }
            public int ThreadStartUpDelay { get; set; }

            public int Duration { get; set; }

            public GeneratorConfiguration()
            {
                StartUpDelay = 0;
                NumberOfThreads = 1;
                ThreadStartUpDelay = 0;
            }

            public int CalculateDuration()
            {
                int result = (Duration * 60) - (StartUpDelay * 60) - (NumberOfThreads * ThreadStartUpDelay);
                return result;
            }
        }
    }


    public class RoleCommunicator
    {
        public static void AbortJob(System.Net.IPEndPoint ep)
        {
            GetChannel(ep).AbortJob();
        }

        public static void AbortAllGenerators()
        {
            foreach (var instance in RoleEnvironment.Roles["LoadGenerator"].Instances)
            {
                RoleCommunicator.AbortJob(instance.InstanceEndpoints["JobEndpoint"].IPEndpoint);
            }
        }

        private static void DeleteActiveJobEntities()
        {
            try
            {                              
                var ActiveJob = AzureTableHelper.GetCloudTable(AppSettings.Table_ActiveJob).ExecuteQuery<Job>(new TableQuery<Job>()).ToList<Job>();
                foreach (var item in ActiveJob)
                {
                    AzureTableHelper.GetCloudTable(AppSettings.Table_ActiveJob).Execute(TableOperation.Delete(item));
                }
            }
            catch (Exception)
            {
                //No need to handle
            }
        }

        public static bool AbortActiveJob()
        {
            try
            {
                DeleteActiveJobEntities();
                AbortAllGenerators();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        private static IJobService GetChannel(System.Net.IPEndPoint ep)
        {
            var factory = new ChannelFactory<LoadGenerator.IJobService>(new NetTcpBinding(SecurityMode.None));
            var address = new EndpointAddress(String.Format("net.tcp://{0}/JobService", ep));
            return factory.CreateChannel(address);  
        }

        public static ServiceHost GetServiceHost()
        {
            Trace.TraceInformation("Starting WCF service host...");

            JobService svc = new JobService();
            var serviceHost = new ServiceHost(svc);

            NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);

            RoleInstanceEndpoint internalEndPoint = RoleEnvironment
                .CurrentRoleInstance
                .InstanceEndpoints["JobEndpoint"];

            serviceHost.AddServiceEndpoint(
                typeof(IJobService),
                binding,
                String.Format("net.tcp://{0}/JobService",
                    internalEndPoint.IPEndpoint));

            try
            {
                serviceHost.Open();
                Trace.TraceInformation("WCF service host started successfully.");
                return serviceHost;
            }
            catch (TimeoutException timeoutException)
            {
                Trace.TraceError("The service operation timed out. {0}",
                                 timeoutException.Message);
                return null;
            }
            catch (CommunicationException communicationException)
            {
                Trace.TraceError("Could not start WCF service host. {0}",
                                 communicationException.Message);
                return null;
            }
        }
    }


}
